package process;

import java.util.Date;

import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import util.DateUtil;

import dal.IAppDataAccessor;

public abstract class AProcess {

	protected final String processName;

	protected IAppDataAccessor appDataAccess;

	protected Date businessDate;

	/**
	 * Default business date behavior, business date = trade date
	 */
	public AProcess() {
		this.processName = getClass().getSimpleName();
	}

	@Required
	public void setAppDataAccess(IAppDataAccessor appDataAccess) {
		this.appDataAccess = appDataAccess;
		Date lastBusinessDate = appDataAccess.getLastProcessedDate(processName);

		if (lastBusinessDate == null) {
			lastBusinessDate = DateUtil.adjustTradeDate(DateUtil.today(), -1);
		}

		businessDate = DateUtil.adjustTradeDate(lastBusinessDate, 1);
	}

	/**
	 * Custom business date behavior, ie, for no business date set to null
	 */
	public AProcess(IAppDataAccessor dataAccess, String processName,
			Date businessDate) {
		this.processName = processName;
		this.appDataAccess = dataAccess;
		this.businessDate = businessDate;
	}

	protected void init() {
		// TODO: validate business date not in the future
		appDataAccess.recordProcessBegin(processName, businessDate);
	}

	protected void finish() {
		appDataAccess.recordProcessComplete(processName);
		System.out.println(processName + " completed successfully.");
	}

	public abstract void doProcess(String args[]);

	public boolean start() {
		return start(null);
	}
	
	// TODO: make this class transactional seperate to any impl classes transactions
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public boolean start(String args[]) {

		try {
			init();
			doProcess(args);
			finish();
			return true;
		} catch (RuntimeException e) {
			error(e);
			return false;
		}
	}

	protected void error(RuntimeException e) {

		// TODO: log error in detail
		e.printStackTrace();

		try {
			appDataAccess.recordProcessError(processName, e);
		} catch (Exception ex) {
			System.out.println("CRITICAL! Error when recording process error:");
			ex.printStackTrace();
		}

		//throw e;
	}
}
